//
// Created by root on 6/5/17.
//


#include <float.h>
#include "../runner.h"

#define OP_LEX(type,lex) Cell* t = make_string(global_scheme, type); \
    Cell* l = make_string(global_scheme, lex); \
    global_scheme->args = cons(global_scheme, t, cons(global_scheme, l, G_NIL)); \
    op_lex(global_scheme); \
    Cell* r = global_scheme->returnValue

static void test_op_lex_boolean_success_case1() {
    OP_LEX("Boolean", "#t");
    assert_string_equal(r->_type, BOOLEAN_TYPE);
    assert_ptr_equal(r, G_TRUE);
}

static void test_op_lex_boolean_success_case2() {
    OP_LEX("Boolean", "#f");
    assert_string_equal(r->_type, BOOLEAN_TYPE);
    assert_ptr_equal(r, G_FALSE);
}

static void test_op_lex_boolean_failure() {
    OP_LEX("Boolean", "#abc");
    assert_string_equal(r->_type, EXCEPTION_TYPE);
    assert_string_equal(car(r)->_string, "NOT_A_BOOLEAN");
}

static void test_op_lex_character_success_case1() {
    OP_LEX("Character", "#\\a");
    assert_string_equal(r->_type, CHARACTER_TYPE);
    assert_int_equal(r->_longValue, 'a');
}

static void test_op_lex_character_success_case2() {
    OP_LEX("Character", "#\\space");
    assert_string_equal(r->_type, CHARACTER_TYPE);
    assert_int_equal(r->_longValue, ' ');
}

static void test_op_lex_character_success_case3() {
    OP_LEX("Character", "#\\tab");
    assert_string_equal(r->_type, CHARACTER_TYPE);
    assert_int_equal(r->_longValue, '\t');
}

static void test_op_lex_character_success_case4() {
    OP_LEX("Character", "#\\return");
    assert_string_equal(r->_type, CHARACTER_TYPE);
    assert_int_equal(r->_longValue, '\r');
}

static void test_op_lex_character_success_case5() {
    OP_LEX("Character", "#\\newline");
    assert_string_equal(r->_type, CHARACTER_TYPE);
    assert_int_equal(r->_longValue, '\n');
}

static void test_op_lex_character_failure() {
    OP_LEX("Character", "#\\not_char");
    assert_string_equal(r->_type, EXCEPTION_TYPE);
    assert_string_equal(car(r)->_string, "NOT_A_CHARACTER");
}

static void test_op_lex_string() {
    OP_LEX("String", "this is a string.");
    assert_string_equal(r->_type, STRING_TYPE);
    assert_string_equal(r->_string, "this is a string.");
}

static void test_op_lex_integer() {
    OP_LEX("Integer", "12345");
    assert_string_equal(r->_type, INTEGER_TYPE);
    assert_int_equal(r->_longValue, 12345);
}

static void test_op_lex_decimal() {
    OP_LEX("Decimal", "3.1415926");
    assert_string_equal(r->_type, DECIMAL_TYPE);
    assert_true(equals_double(r->_doubleValue, 3.1415926));
}

static void test_op_lex_symbol() {
    //
}

static void test_op_lex_failure() {
    OP_LEX("NotLex", "not a lex string.");
    assert_string_equal(r->_type, EXCEPTION_TYPE);
    assert_string_equal(car(r)->_string, "UNDEFINED_LEX");
}

int main(int argc, char **argv) {
    const struct CMUnitTest tests[] = {
            cmocka_unit_test(test_op_lex_boolean_success_case1),
            cmocka_unit_test(test_op_lex_boolean_success_case2),
            cmocka_unit_test(test_op_lex_boolean_failure),
            cmocka_unit_test(test_op_lex_character_success_case1),
            cmocka_unit_test(test_op_lex_character_success_case2),
            cmocka_unit_test(test_op_lex_character_success_case3),
            cmocka_unit_test(test_op_lex_character_success_case4),
            cmocka_unit_test(test_op_lex_character_success_case5),
            cmocka_unit_test(test_op_lex_character_failure),
            cmocka_unit_test(test_op_lex_string),
            cmocka_unit_test(test_op_lex_integer),
            cmocka_unit_test(test_op_lex_decimal),
            cmocka_unit_test(test_op_lex_failure),
    };
    return cmocka_run_group_tests(tests, setup_scheme, teardown_scheme);
}
